package geektime.spring.springbucks;

import cn.hutool.http.HttpUtil;
import geektime.spring.springbucks.service.CoffeeService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.*;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;

@Slf4j
@EnableTransactionManagement
@SpringBootApplication
@MapperScan("geektime.spring.springbucks.mapper")
public class SpringBucksApplication implements ApplicationRunner {
	@Autowired
	private CoffeeService coffeeService;
	@Autowired
	private RestTemplate restTemplate;

	public static void main(String[] args) {
		SpringApplication.run(SpringBucksApplication.class, args);
	}

	@Bean
	public RestTemplate restTemplate(){
		RestTemplate template = new RestTemplate();
		// messageConverters是RestTemplate的一个final修饰的List类型的成员变量
		// messageConverters的第二个元素存储的是StringHttpMessageConverter类型的消息转换器
		// StringHttpMessageConverter的默认字符集是ISO-8859-1,在此处设置utf-8字符集避免产生乱码
		template.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("utf-8")));
		return template;
	}


	@Override
	public void run(ApplicationArguments args) throws Exception {

		String reqUrl = "http://localhost:8080/coffee/getCoffeeByNameForJson";//指定URL
		Map<String, Object> paramMap = new HashMap<>();//存放参数
		paramMap.put("coffeeName", "o");
		HashMap<String, String> headers = new HashMap<>();//存放请求头，可以存放多个请求头
		String result ="";

		//1.HttpURLConnection
		result = this.httpReqByHttpURLConnection(reqUrl, paramMap.toString());
		log.info("HttpURLConnection方式返回结果result==>{}", result);

		//2.RestTemplate
		result = this.httpReqByRestTemplate(reqUrl, paramMap.toString());
		log.info("RestTemplate方式返回结果result==>{}", result);

		//3.HttpClient
		result = this.httpReqByHttpClient(reqUrl, paramMap);
		log.info("HttpClient方式返回结果result==>{}", result);

		//4.okhttp3
		result = this.httpReqByOkHttp3(reqUrl, paramMap.toString());
		log.info("okhttp3方式返回结果result==>{}", result);

		//5.hutool
		//发送post请求并接收响应数据
		 result= HttpUtil.createPost(reqUrl).addHeaders(headers).form(paramMap).execute().body();
		log.info("hutool方式返回结果result==>{}", result);
	}

	/**
	 * 1.HttpURLConnection
	 * @param url
	 * @param param
	 * @return
	 */
	private String httpReqByHttpURLConnection(String url,String param){
		StringBuffer result = new StringBuffer();
		HttpURLConnection conn = null;
		OutputStream out = null;
		BufferedReader reader = null;
		try {
			URL restUrl = new URL(url);
			conn = (HttpURLConnection) restUrl.openConnection();
			conn.setRequestMethod("POST");
			conn.setDoOutput(true);
			conn.setDoInput(true);

			conn.setRequestProperty("accept", "*/*");
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");

			conn.connect();
			out = conn.getOutputStream();
			out.write(param.getBytes());
			out.flush();

			int responseCode = conn.getResponseCode();
			if(responseCode != 200){
				throw new RuntimeException("Error responseCode:" + responseCode);
			}

			String output = null;
			reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
			while((output=reader.readLine()) != null){
				result.append(output);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("调用接口出错：param+"+param);
		} finally {
			try {
				if(reader != null){
					reader.close();
				}
				if(out != null){
					out.close();
				}
				if(conn != null){
					conn.disconnect();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}

		return result.toString();
	}

	/**
	 * 2.RestTemplate
	 * @param url
	 * @param jsonParam
	 * @return
	 */
	public String httpReqByRestTemplate(String url, String jsonParam){
		// 自定义请求头
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.setAcceptCharset(Collections.singletonList(Charset.forName("utf-8")));
		headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
		// 参数
		HttpEntity<String> entity = new HttpEntity<String>(jsonParam, headers);
		// POST方式请求
		ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
		if(responseEntity == null){
			return null;
		}
		return responseEntity.getBody().toString();
	}

	/**
	 *
	 * @param url
	 * @param pramMap
	 * @return
	 * @throws Exception
	 */
	public String httpReqByHttpClient(String url, Map<String, Object> pramMap) throws Exception {
		String result = null;
		// DefaultHttpClient已过时,使用CloseableHttpClient替代
		CloseableHttpClient closeableHttpClient = null;
		CloseableHttpResponse response = null;
		try {
			closeableHttpClient = HttpClients.createDefault();
			HttpPost postRequest = new HttpPost(url);
			List<NameValuePair> pairs = new ArrayList<>();
			if(pramMap!=null && pramMap.size() > 0){
				for (Map.Entry<String, Object> entry : pramMap.entrySet()) {
					pairs.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
				}
			}
			UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(pairs, "utf-8");
			postRequest.setEntity(formEntity);

			response = closeableHttpClient.execute(postRequest);
			if(response!=null && response.getStatusLine().getStatusCode()==HttpStatus.OK.value()){
				result = EntityUtils.toString(response.getEntity(), "utf-8");
			}else{
				throw new Exception("post请求失败,url" + url);
			}

		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		} finally {
			try {
				if(response != null){
					response.close();
				}
				if(closeableHttpClient != null){
					closeableHttpClient.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}


	/**
	 * OkHttp3
	 * @param url
	 * @param json
	 * @return
	 * @throws IOException
	 */
	private String httpReqByOkHttp3(String url, String json) throws IOException {
		okhttp3.MediaType JSON = okhttp3.MediaType.parse("application/json; charset=utf-8");
		OkHttpClient client = new OkHttpClient();
		RequestBody body = RequestBody.create(JSON, json);
		Request request = new Request.Builder()
				.url(url)
				.post(body)
				.build();
		Response response = client.newCall(request).execute();
		return response.body().string();
	}
}

